package com.srmt.document.feishu.internal;

import com.lark.oapi.Client;
import com.lark.oapi.service.drive.v1.enums.MemberMemberTypeEnum;
import com.srmt.feishu.client.FeishuClient;
import com.lark.oapi.core.request.RequestOptions;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.docx.v1.model.*;
import com.lark.oapi.service.drive.v1.model.*;
import com.google.gson.JsonParser;
import java.nio.charset.StandardCharsets;
import com.srmt.document.api.DocumentManager;
import com.srmt.common.config.ApplicationConfig;
import com.srmt.document.exception.DocumentException;
import com.srmt.document.exception.DocumentNotFoundException;
import com.srmt.document.exception.DocumentOperationException;
import com.srmt.document.exception.PermissionDeniedException;
import com.srmt.document.model.DocumentInfo;
import com.srmt.document.model.PermissionSetting;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import static com.lark.oapi.service.drive.v1.enums.MemberMemberTypeEnum.OPEN_CHAT;

/**
 * 飞书文档管理器实现
 * 负责文档的创建、权限管理、基础操作
 * 
 * @author srmt
 * @since 1.0.0
 */
public class FeishuDocumentManager implements DocumentManager {
    
    private static final Logger logger = LoggerFactory.getLogger(FeishuDocumentManager.class);
    
    private final FeishuClient client;
    private final ApplicationConfig applicationConfig;
    
    // 提供getter方法供测试使用
    public FeishuClient getClient() {
        return client;
    }
    
    
    /**
     * 使用ApplicationConfig构造（推荐）
     */
    public FeishuDocumentManager(FeishuClient client, ApplicationConfig applicationConfig) {
        if (client == null) {
            throw new IllegalArgumentException("客户端不能为null");
        }
        if (applicationConfig == null) {
            throw new IllegalArgumentException("应用配置对象不能为null");
        }
        this.client = client;
        this.applicationConfig = applicationConfig;
    }
    
    
    @Override
    public String createFromTemplate(String templateId, String title, String folderToken) throws DocumentException {
        logger.debug("创建 document from template: {}, title: {}", templateId, title);
        
        try {
            if (templateId != null && !templateId.isEmpty()) {
                // 使用飞书文件复制API从模板创建文档
                logger.info("创建 document from template: {}", templateId);
                
                // 使用Drive API的文件复制功能
                CopyFileReqBody.Builder reqBodyBuilder = CopyFileReqBody.newBuilder()
                        .name(title)
                        .type("docx");  // 指定为docx类型
                
                // 设置文件夹token
                if (folderToken != null && !folderToken.isEmpty()) {
                    reqBodyBuilder.folderToken(folderToken);
                } else {
                    String defaultFolderToken = applicationConfig.getFeishu().getDefaultFolderToken();
                    if (defaultFolderToken != null && !defaultFolderToken.isEmpty()) {
                        reqBodyBuilder.folderToken(defaultFolderToken);
                    } else {
                        // 如果没有指定文件夹，必须提供一个有效的folderToken
                        throw new DocumentOperationException("从模板创建文档时需要文件夹令牌");
                    }
                }
                
                CopyFileReq req = CopyFileReq.newBuilder()
                    .fileToken(templateId)
                    .copyFileReqBody(reqBodyBuilder.build())
                    .build();

                // copyFile现在直接返回新文件的token
                String newDocId = client.drive().copyFile(req);
                logger.info("文档 created from template successfully: {}", newDocId);

                return newDocId;
            } else {
                // 创建空白文档
                CreateDocumentReqBody.Builder reqBodyBuilder = CreateDocumentReqBody.newBuilder()
                        .title(title);
                
                // 设置文件夹token
                if (folderToken != null && !folderToken.isEmpty()) {
                    reqBodyBuilder.folderToken(folderToken);
                } else {
                    String defaultFolderToken = applicationConfig.getFeishu().getDefaultFolderToken();
                    if (defaultFolderToken != null && !defaultFolderToken.isEmpty()) {
                        reqBodyBuilder.folderToken(defaultFolderToken);
                    }
                }
                // 空白文档可以不指定文件夹token，会创建在根目录
                
                CreateDocumentReqBody reqBody = reqBodyBuilder.build();
                
                CreateDocumentReq req = CreateDocumentReq.newBuilder()
                        .createDocumentReqBody(reqBody)
                        .build();

                // createDocument现在直接返回Document对象
                Document doc = client.docx().createDocument(req);
                String documentId = doc.getDocumentId();
                logger.info("文档 created successfully: {}", documentId);

                return documentId;
            }
            
        } catch (Exception e) {
            if (e instanceof DocumentException) {
                throw (DocumentException) e;
            }
            throw new DocumentException("创建文档失败", e);
        }
    }
    
    @Override
    public void setPermissions(String docId, PermissionSetting permission) 
            throws PermissionDeniedException, DocumentNotFoundException {
        logger.debug("设置 permissions for document: {}", docId);
        
        try {
            // 构建权限请求
            // 注意：飞书的权限API在drive服务下
            
            boolean needNotification = permission.isNeedNotification();
            
            // 处理只读用户
            if (permission.getReadUsers() != null) {
                for (String userId : permission.getReadUsers()) {
                    String memberType = detectMemberType(userId);
                    createPermissionMember(docId, userId, "view", memberType, needNotification);
                }
            }
            
            // 处理可写用户
            if (permission.getWriteUsers() != null) {
                for (String userId : permission.getWriteUsers()) {
                    String memberType = detectMemberType(userId);
                    createPermissionMember(docId, userId, "edit", memberType, needNotification);
                }
            }
            
            // 处理管理员用户
            if (permission.getAdminUsers() != null) {
                for (String userId : permission.getAdminUsers()) {
                    String memberType = detectMemberType(userId);
                    createPermissionMember(docId, userId, "full_access", memberType, needNotification);
                }
            }
            
            // 处理评论用户（映射为edit权限）
            if (permission.getCommentUsers() != null) {
                for (String userId : permission.getCommentUsers()) {
                    String memberType = detectMemberType(userId);
                    createPermissionMember(docId, userId, "edit", memberType, needNotification);
                }
            }
            
            // 处理公开权限
            if (permission.isPublic()) {
                // 设置链接分享权限
                updateLinkPermission(docId, permission.isAllowComment() ? "comment" : "view");
            }
            
            logger.info("成功为文档设置权限: {}", docId);
            
        } catch (Exception e) {
            if (e instanceof PermissionDeniedException) {
                throw (PermissionDeniedException) e;
            }
            if (e instanceof DocumentNotFoundException) {
                throw (DocumentNotFoundException) e;
            }
            throw new PermissionDeniedException("设置权限失败: " + e.getMessage());
        }
    }
    
    @Override
    public void adjustPermissions(String docId, String userId, String permission) 
            throws PermissionDeniedException, DocumentNotFoundException {
        logger.debug("调整文档权限 - 文档: {}, 用户: {}, 权限: {}",
                     docId, userId, permission);
        
        try {
            // 映射权限类型
            String feishuPermission = mapPermissionToFeishu(permission);
            String memberType = detectMemberType(userId);
            
            // 尝试更新权限，如果失败则创建新权限
            try {
                updatePermissionMember(docId, userId, feishuPermission, memberType, false);
            } catch (DocumentOperationException e) {
                // 如果更新失败，可能是权限不存在，尝试创建
                logger.debug("更新 failed, trying to create permission: {}", e.getMessage());
                createPermissionMember(docId, userId, feishuPermission, memberType, false);
            }
            logger.info("成功调整用户的权限: {} on document: {}", 
                       userId, docId);
            
        } catch (Exception e) {
            if (e instanceof PermissionDeniedException) {
                throw (PermissionDeniedException) e;
            }
            if (e instanceof DocumentNotFoundException) {
                throw (DocumentNotFoundException) e;
            }
            throw new PermissionDeniedException("调整权限失败: " + e.getMessage());
        }
    }
    
    @Override
    public void removePermission(String docId, String userId)
            throws PermissionDeniedException, DocumentNotFoundException {
        logger.debug("删除用户权限 - 用户: {}, 文档: {}", userId, docId);
        
        try {
            // 检测用户ID类型
            String memberType = detectMemberType(userId);
            
            // 调用内部方法删除权限
            deletePermissionMember(docId, userId, memberType);
            
            logger.info("权限s removed successfully for user: {} on document: {}", 
                       userId, docId);
            
        } catch (Exception e) {
            if (e instanceof PermissionDeniedException) {
                throw (PermissionDeniedException) e;
            }
            if (e instanceof DocumentNotFoundException) {
                throw (DocumentNotFoundException) e;
            }
            throw new PermissionDeniedException("移除权限失败: " + e.getMessage());
        }
    }
    
    @Override
    public DocumentInfo getDocumentInfo(String docId) throws DocumentNotFoundException {
        logger.debug("获取 document info for: {}", docId);
        
        try {
            GetDocumentReq req = GetDocumentReq.newBuilder()
                    .documentId(docId)
                    .build();

            // getDocument现在直接返回Document对象，失败时抛出FeishuApiException
            Document doc = client.docx().getDocument(req);

            // 构建DocumentInfo
            DocumentInfo info = new DocumentInfo();
            info.setDocumentId(doc.getDocumentId());
            info.setTitle(doc.getTitle());
            info.setVersion(String.valueOf(doc.getRevisionId()));

            // 获取文档URL
            String docUrl = getDocumentUrl(docId);
            info.setUrl(docUrl);

            // 设置时间戳（如果API提供）
            info.setCreatedAt(new Date());
            info.setUpdatedAt(new Date());

            return info;

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            // 处理特定的API错误码
            if (e.getCode() == 99999 || e.getMessage().contains("not found")) {
                throw new DocumentNotFoundException("文档 未找到: " + docId);
            }
            throw new DocumentNotFoundException("获取文档信息失败: " + e.getMessage());
        } catch (DocumentNotFoundException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentNotFoundException("获取文档信息失败: " + e.getMessage());
        }
    }
    
    @Override
    public void deleteDocument(String docId) throws DocumentException, DocumentNotFoundException {
        logger.debug("删除 document: {}", docId);
        
        try {
            // 使用Drive API删除文档
            // 在飞书中，docx文档的document_id可以直接作为file_token使用
            com.lark.oapi.service.drive.v1.model.DeleteFileReq req =
                    com.lark.oapi.service.drive.v1.model.DeleteFileReq.newBuilder()
                            .fileToken(docId)
                            .type("docx")  // 指定文档类型为docx
                            .build();

            // deleteFile现在不返回值，失败时抛出FeishuApiException
            client.drive().deleteFile(req);
            logger.info("成功删除文档: {}", docId);

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            // 处理特定的API错误码
            if (e.getCode() == 99999 || e.getMessage().contains("not found")) {
                throw new DocumentNotFoundException("文档 未找到: " + docId);
            }
            throw new DocumentException("删除文档失败: " + e.getMessage());
        } catch (DocumentNotFoundException e) {
            throw e;
        } catch (Exception e) {
            if (e instanceof DocumentException) {
                throw (DocumentException) e;
            }
            throw new DocumentException("删除文档失败", e);
        }
    }
    
    @Override
    public String copyDocument(String sourceDocId, String newTitle, String folderToken) 
            throws DocumentException, DocumentNotFoundException {
        logger.debug("复制 document: {} to: {} in folder: {}", sourceDocId, newTitle, folderToken);
        
        try {
            // 使用Drive API的文件复制功能
            CopyFileReqBody.Builder reqBodyBuilder = CopyFileReqBody.newBuilder()
                    .name(newTitle)
                    .type("docx");  // 指定为docx类型
            
            // 设置文件夹token
            if (folderToken != null && !folderToken.isEmpty()) {
                reqBodyBuilder.folderToken(folderToken);
            } else {
                String defaultFolderToken = applicationConfig.getFeishu().getDefaultFolderToken();
                if (defaultFolderToken != null && !defaultFolderToken.isEmpty()) {
                    reqBodyBuilder.folderToken(defaultFolderToken);
                } else {
                    // 如果没有指定文件夹，必须提供一个有效的folderToken
                    throw new DocumentOperationException("复制文档时需要文件夹令牌");
                }
            }
            
            CopyFileReq req = CopyFileReq.newBuilder()
                .fileToken(sourceDocId)
                .copyFileReqBody(reqBodyBuilder.build())
                .build();

            // copyFile现在直接返回新文件的token
            String newDocId = client.drive().copyFile(req);
            logger.info("文档 copied successfully from {} to {}", sourceDocId, newDocId);

            return newDocId;

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            // 处理特定的API错误码
            if (e.getCode() == 99999 || e.getMessage().contains("not found")) {
                throw new DocumentNotFoundException("Source document 未找到: " + sourceDocId);
            }
            throw new DocumentException("复制文档失败: " + e.getMessage());
        } catch (DocumentException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentException("复制文档失败", e);
        }
    }

    
    @Override
    public String getDocumentUrl(String docId) throws DocumentNotFoundException {
        logger.debug("获取文档URL: {}", docId);
        
        // 构建飞书文档URL
        // 格式通常为：https://[domain]/docx/[documentId]
        String baseUrl = "https://open.feishu.cn";
        
        // 替换open域名为普通域名
        if (baseUrl.contains("open.feishu.cn")) {
            baseUrl = "https://feishu.cn";
        } else if (baseUrl.contains("open.larksuite.com")) {
            baseUrl = "https://larksuite.com";
        }
        
        String docUrl = baseUrl + "/docx/" + docId;
        logger.debug("文档 URL: {}", docUrl);
        
        return docUrl;
    }
    
    // ========== 私有辅助方法 ==========
    
    /**
     * 创建权限成员 - 为用户或组添加文档权限
     */
    private void createPermissionMember(String token, String memberId, String perm, 
                                      String memberType, boolean needNotification) 
            throws DocumentOperationException {
        logger.debug("创建 permission for member {} with {} permission on document {}", 
                    memberId, perm, token);
        
        try {
            // 构建权限请求
            CreatePermissionMemberReq req = CreatePermissionMemberReq.newBuilder()
                .token(token)
                .type("docx")  // 文档类型
                .needNotification(needNotification)
                .baseMember(BaseMember.newBuilder()
                    .memberType(memberType)  // "userid" 或 "openid"
                    .memberId(memberId)
                    .perm(perm)  // "view", "edit", "full_access"
                    .permType("container")  // 固定值
                    .type("user")  // "user" 或 "group"
                    .build())
                .build();

            // createPermissionMember现在直接返回BaseMember对象，失败时抛出FeishuApiException
            client.drive().createPermissionMember(req);
            logger.info("权限 created successfully for member {} on document {}",
                       memberId, token);

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            // 根据错误码抛出不同异常
            if (e.getCode() == 1061102) {
                throw new PermissionDeniedException(String.format("权限被拒绝: %s (错误码: %d)",
                    e.getMessage(), e.getCode()));
            } else if (e.getCode() == 1061101) {
                throw new DocumentNotFoundException(String.format("文档未找到: %s (错误码: %d)",
                    token, e.getCode()));
            }
            throw new DocumentOperationException(String.format("创建权限失败: %s (错误码: %d)",
                e.getMessage(), e.getCode()));
        } catch (DocumentOperationException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentOperationException("创建权限失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 更新权限成员 - 修改现有权限级别
     */
    private void updatePermissionMember(String token, String memberId, String perm, 
                                      String memberType, boolean needNotification) 
            throws DocumentOperationException {
        logger.debug("更新成员的权限 {} to {} permission on document {}", 
                    memberId, perm, token);
        
        try {
            // 构建权限更新请求
            UpdatePermissionMemberReq req = UpdatePermissionMemberReq.newBuilder()
                .token(token)
                .memberId(memberId)
                .type("docx")
                .needNotification(needNotification)
                .baseMember(BaseMember.newBuilder()
                    .memberType(memberType)
                    .perm(perm)
                    .permType("container")
                    .type("user")
                    .build())
                .build();

            // updatePermissionMember现在直接返回BaseMember对象，失败时抛出FeishuApiException
            client.drive().updatePermissionMember(req);
            logger.info("权限 updated successfully for member {} on document {}",
                       memberId, token);

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            if (e.getCode() == 1061102) {
                throw new PermissionDeniedException(String.format("权限被拒绝: %s (错误码: %d)",
                    e.getMessage(), e.getCode()));
            } else if (e.getCode() == 1061101) {
                throw new DocumentNotFoundException(String.format("文档未找到: %s (错误码: %d)",
                    token, e.getCode()));
            }
            throw new DocumentOperationException(String.format("更新权限失败: %s (错误码: %d)",
                e.getMessage(), e.getCode()));
        } catch (DocumentOperationException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentOperationException("更新权限失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 删除权限成员 - 移除用户或组的文档权限
     */
    private void deletePermissionMember(String token, String memberId, String memberType) 
            throws DocumentOperationException {
        logger.debug("删除 permission for member {} on document {}", memberId, token);
        
        try {
            // 构建权限删除请求
            DeletePermissionMemberReq req = DeletePermissionMemberReq.newBuilder()
                .token(token)
                .memberId(memberId)
                .type("docx")
                .memberType(memberType)
                .deletePermissionMemberReqBody(DeletePermissionMemberReqBody.newBuilder()
                    .type("user")
                    .permType("container")
                    .build())
                .build();

            // deletePermissionMember现在不返回值，失败时抛出FeishuApiException
            client.drive().deletePermissionMember(req);
            logger.info("成功删除成员的权限 {} on document {}",
                       memberId, token);

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            if (e.getCode() == 1061102) {
                throw new PermissionDeniedException(String.format("权限被拒绝: %s (错误码: %d)",
                    e.getMessage(), e.getCode()));
            } else if (e.getCode() == 1061101) {
                throw new DocumentNotFoundException(String.format("文档未找到: %s (错误码: %d)",
                    token, e.getCode()));
            }
            throw new DocumentOperationException(String.format("删除权限失败: %s (错误码: %d)",
                e.getMessage(), e.getCode()));
        } catch (DocumentOperationException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentOperationException("删除权限失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 检测用户ID类型 - 自动判断是 userid 还是 openid
     */
    private String detectMemberType(String memberId) {
        if (memberId == null || memberId.isEmpty()) {
            throw new IllegalArgumentException("Member ID 不能为null or empty");
        }

        // openid通常以 "ou_" 开头
        if (memberId.startsWith("ou_")) {
            return "openid";
        }
        // userid通常是其他格式
        return "userid";
    }
    
    /**
     * 映射SDK权限到飞书API权限
     */
    private String mapPermissionToFeishu(String permission) {
        if (permission == null) {
            return "view";
        }
        
        switch (permission.toLowerCase()) {
            case "view":
            case "read":
            case "reader":
                return "view";
            case "edit":
            case "write":
            case "writer":
                return "edit";
            case "comment":
            case "commenter":
                return "edit"; // 飞书中评论权限包含在edit中
            case "full_access":
            case "owner":
            case "admin":
                return "full_access";
            default:
                logger.warn("未知的权限类型: {},默认使用view", permission);
                return "view";
        }
    }

    
    /**
     * 更新链接分享权限
     */
    private void updateLinkPermission(String docId, String permission) 
            throws DocumentOperationException {
        logger.debug("更新文档{}的链接权限: {}", docId, permission);
        // 设置链接分享权限
        logger.info("文档{}的链接权限已更新: {}", docId, permission);
        throw new UnsupportedOperationException("暂不支持调整链接分享权限");
    }
    
    /**
     * 获取文档的所有权限成员列表
     */
    private Member[] listPermissionMembers(String token) 
            throws DocumentOperationException, DocumentNotFoundException {
        logger.debug("列出文档{}的权限成员", token);
        
        try {
            ListPermissionMemberReq req = ListPermissionMemberReq.newBuilder()
                    .token(token)
                    .type("docx")
                    .fields("*")
                    .permType("container")
                    .build();

            // listPermissionMember现在直接返回BaseMember[]，失败时抛出FeishuApiException
            Member[] baseMembers = client.drive().listPermissionMember(req);

            if (baseMembers == null || baseMembers.length == 0) {
                return new Member[0];
            }

            // SDK实际返回的是Member[]实例（Member继承自BaseMember）
            // 使用Arrays.copyOf进行类型安全的转换
            return java.util.Arrays.copyOf(baseMembers, baseMembers.length, Member[].class);

        } catch (com.srmt.feishu.client.exception.FeishuApiException e) {
            // 检查特定错误码
            if (e.getCode() == 1061101 || e.getCode() == 99999 ||
                e.getCode() == 1063001 || // Invalid parameter也可能表示文档不存在
                (e.getMessage() != null && e.getMessage().contains("not found"))) {
                throw new DocumentNotFoundException(
                    String.format("文档未找到: %s (错误码: %d)", token, e.getCode()));
            } else if (e.getCode() == 1061102) {
                throw new PermissionDeniedException(
                    String.format("权限被拒绝: %s (错误码: %d)", e.getMessage(), e.getCode()));
            }

            throw new DocumentOperationException(
                String.format("列出权限失败: %s (错误码: %d)",
                    e.getMessage(), e.getCode()));
        } catch (DocumentNotFoundException | PermissionDeniedException e) {
            throw e;
        } catch (DocumentOperationException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentOperationException("列出权限失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 清空文档的所有权限（除了所有者）
     */
    private void clearAllPermissions(String token) 
            throws DocumentOperationException, DocumentNotFoundException, PermissionDeniedException {
        logger.debug("清除文档{}的所有权限", token);
        
        // 获取所有现有权限
        Member[] members = listPermissionMembers(token);
        
        // 逐个删除权限（跳过所有者）
        int deletedCount = 0;
        int skippedCount = 0;
        for (Member member : members) {
            try {
                deletePermissionMember(token, member.getMemberId(), member.getMemberType());
                deletedCount++;
                logger.debug("已删除成员的权限: {}", member.getMemberId());
            } catch (Exception e) {
                logger.warn("删除成员{}的权限失败: {}",
                           member.getMemberId(), e.getMessage());
            }
        }
        
        logger.info("已清除文档{}的{}个权限(跳过{}个所有者)",
                   token, deletedCount, skippedCount);
    }
    
    @Override
    public void refreshPermissions(String docId, PermissionSetting permission) 
            throws PermissionDeniedException, DocumentNotFoundException {
        logger.info("刷新文档{}的权限", docId);
        
        try {
            // 步骤1：清空所有现有权限（除了owner）
            clearAllPermissions(docId);
            // 步骤3：设置新权限（复用现有的setPermissions逻辑）
            setPermissions(docId, permission);
            
            logger.info("成功刷新文档权限: {}", docId);
            
        } catch (PermissionDeniedException | DocumentNotFoundException e) {
            throw e;
        } catch (DocumentOperationException e) {
            // 将DocumentOperationException转换为PermissionDeniedException
            throw new PermissionDeniedException(
                "刷新权限失败: " + e.getMessage());
        } catch (Exception e) {
            throw new PermissionDeniedException(
                "刷新权限失败: " + e.getMessage());
        }
    }

}